require "renoise.http.json"

local FINAL_FRAME = 128
local HAS_MASK    = 128
local OPCODE_MASK = 15
local LENGTH_MASK = 127

local OPCODE_CONTINUE = 0
local OPCODE_TEXT     = 1

-- TODO Handle multi package messages
-- TODO Handle multi frame messages

class "WebSocketDecoder"
  
  function WebSocketDecoder:__init()
    self.buffer = ""
    self.headerParsed = false
    self.frameComplete = false  
    self.isFinal = false
    self.opcode = 0
    self.hasMask = 0
    self.length = 0
    self.maskPosition = 0
    self.mask = 0
  end
  
  function WebSocketDecoder:decode(data)
    if (not self.headerParsed) then
      data = self:parseHeader(data)
      self.headerParsed = true
    end
    
    self.buffer = self.buffer .. self:parseContent(data)
    
    if(self.length - #self.buffer == 0) then 
      self.frameComplete = true
      self.headerParsed = false
    end
    
    if (self.frameComplete and self.isFinal) then
      print("Received message: ", self.buffer)
      return true
    else
      return false
    end
  end

  function WebSocketDecoder:parseHeader(message)
    self.isFinal = bit.bxor(message:byte(1), FINAL_FRAME) > 0
    self.opcode  = bit.band(message:byte(1), OPCODE_MASK)
    self.hasMask = bit.bxor(message:byte(2), HAS_MASK) > 0
    self.length  = bit.band(message:byte(2), LENGTH_MASK)
        
    local maskStart = 3
    
    -- 16 bit self.length
    if (self.length == 126) then
      maskStart = maskStart + 2
      self.length = bit.bor(message:byte(4), bit.lshift(message:byte(3), 8))
    end
  
    -- 64 bit self.length (NOT TESTED)
    if (self.length == 127) then
      maskStart = maskStart + 8
      self.length = 0
      for i = 0, 7 do
        self.length = self.length + bit.lshift(message:byte(11 - i), 8 * i)
      end
    end
    
    local contentStart = maskStart
    local payload = ''
    if (self.hasMask) then
      contentStart = maskStart + 4
      self.mask = {message:byte(maskStart, contentStart - 1)}
      self.maskPosition = 1
    end
    
    return message:sub(contentStart)
  end 
    
  function WebSocketDecoder:parseContent(message)
    local payload = ""
    for k = 1, #message do
        local b = message:byte(k)
        payload = payload .. string.char(bit.bxor(b, self.mask[self.maskPosition]))
        self.maskPosition = math.mod(self.maskPosition, 4) + 1
      end
    return payload
  end

function encodeWebSocketMessage(message)
  message = json.encode(message)
  print("Sent message: ", message)
  local msg = string.char(bit.bor(FINAL_FRAME, OPCODE_TEXT))
  -- No masking
  if (#message > 125) then 
    msg = msg .. string.char(126)
    msg = msg .. string.char(bit.rshift(#message, 8))
    msg = msg .. string.char(bit.band(#message, 255))
  else
    msg = msg .. string.char(#message)
  end
  return msg .. message
end
